﻿/*
*	Copyright(c) 2020 lutianming email：641471957@qq.com
*
*	Sheeps may be copied only under the terms of the GNU Affero General Public License v3.0
*/

#include "framework.h"
#include "ServerStress.h"
#include "ServerTask.h"
#include "ServerHook.h"
#ifdef __WINDOWS__
#include "io.h"
#include "direct.h"
#else
#include "dirent.h"
#endif

typedef int (*serverStress_cmd_cb) (HSOCKET hsock, ServerProtocol* proto, int cmdNO, cJSON* root, cJSON* res);

bool StressServerInit()
{
	api_samples = config_get_int_value("server", "api_samples", 0);
	return true;
}

static int ResponseMsg(HSOCKET hsock, int cmdNo, cJSON* res)
{
	int len = 0;
	char* data = cJSON_PrintUnformatted(res, &len);

	t_stress_protocol_head head = {0x0};
	head.cmdNo = cmdNo;
	head.msgLen = len + SHEEPS_HEAD_SIZE;
	head.binary = 0;

	char* buf = (char*)malloc(head.msgLen);
	if (buf) {
		memcpy(buf, &head, SHEEPS_HEAD_SIZE);
		memcpy(buf + SHEEPS_HEAD_SIZE, data, len);
		HsocketSend(hsock, buf, head.msgLen);
		free(buf);
	}
	LOG(slogid, LOG_DEBUG, "%s:%d [%d %d:%s]\r\n", __func__, __LINE__, len, cmdNo, data);
	cJSON_free(data);
	return 0;
}

#ifdef __WINDOWS__
static void getFiles(char* dir_path, std::map<std::string, t_file_update>* files){
	intptr_t hFile = 0;
	struct _finddata_t fileinfo;

	char allfile[256] = { 0x0 };
	snprintf(allfile, sizeof(allfile), "%s/*", dir_path);

	char fullpath[256] = { 0x0 };
	if ((hFile = _findfirst(allfile, &fileinfo)) != -1){
		do{
			memset(fullpath, 0, sizeof(fullpath));
			if ((fileinfo.attrib & _A_SUBDIR)){
				snprintf(fullpath, sizeof(fullpath), "%s/%s", dir_path, fileinfo.name);
				if (strcmp(fileinfo.name, ".") == 0 || strcmp(fileinfo.name, "..") == 0)
					continue;
				getFiles(fullpath, files);
			}
			else{
				snprintf(fullpath, sizeof(fullpath), "%s/%s", dir_path, fileinfo.name);
				char shortpath[128] = { 0x0 };
				snprintf(shortpath, sizeof(shortpath), "%s", fullpath + strlen(EXE_Path));

				t_file_update info = { 0x0 };
				getfilemd5view(fullpath, info.fmd5, sizeof(info.fmd5));

#ifdef _WIN64
				struct _stat64 finfo;
				_stat64(fullpath, &finfo);
#else
				struct _stat32 finfo;
				_stat32(fullpath, &finfo);
#endif //  _WIN64
				info.size = finfo.st_size;
				files->insert(std::pair<std::string, t_file_update>(shortpath, info));
			}
		} while (_findnext(hFile, &fileinfo) == 0);
		_findclose(hFile);
	}
}
#else
static void getFiles(char* dir_path, std::map<std::string, t_file_update>* files){
	DIR* dir;
	struct dirent* ptr;
	char fullpath[256] = { 0x0 };
	if ((dir = opendir(dir_path)) == NULL)
		return;
	while ((ptr = readdir(dir)) != NULL){
		if (ptr->d_type == DT_DIR){
			if (strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0)
				continue;
			snprintf(fullpath, sizeof(fullpath), "%s/%s", dir_path, ptr->d_name);
			getFiles(fullpath, files);
		}
		else{
			snprintf(fullpath, sizeof(fullpath), "%s/%s", dir_path, ptr->d_name);
			char shortpath[128] = { 0x0 };
			snprintf(shortpath, sizeof(shortpath), "%s", fullpath + strlen(EXE_Path));

			t_file_update info = { 0x0 };
			getfilemd5view(fullpath, info.fmd5, sizeof(info.fmd5));

			struct stat finfo;
			stat(fullpath, &finfo);
			info.size = finfo.st_size;

			files->insert(std::pair<std::string, t_file_update>(shortpath, info));
		}
		
	}
	closedir(dir);
}
#endif

int sync_files(HSOCKET hsock, int projectid){
	std::map<std::string, t_file_update> updatefile;
	getFiles(ProjectPath, &updatefile);

	cJSON* syncfiles = cJSON_CreateObject();
	cJSON* array = cJSON_CreateArray();
	cJSON_AddItemToObject(syncfiles, "filelist", array);
	std::map<std::string, t_file_update>::iterator iter;
	for (iter = updatefile.begin(); iter != updatefile.end(); ++iter){
		cJSON* item = cJSON_CreateObject();
		cJSON_AddStringToObject(item, "File", iter->first.c_str());
		cJSON_AddNumberToObject(item, "Size", (const double)(iter->second.size));
		cJSON_AddStringToObject(item, "Md5", iter->second.fmd5);
		cJSON_AddItemToArray(array, item);
	}

	ResponseMsg(hsock, S2C_Agent_File_Sync, syncfiles);
	cJSON_Delete(syncfiles);
	return 0;
}

int push_authcode() {
	char msg[1024] = { 0x0 };
	int len = snprintf(msg, sizeof(msg), "{\"AuthCode\":\"\"}");

	t_stress_protocol_head head = {0x0};
	head.cmdNo = C2S_Agent_Report_Info;
	head.msgLen = len + SHEEPS_HEAD_SIZE;

	char* buf = (char*)malloc(head.msgLen);
	if (!buf) return -1;
	memcpy(buf, &head, SHEEPS_HEAD_SIZE);
	memcpy(buf + SHEEPS_HEAD_SIZE, msg, len);

	t_project_config* projectcfg;
	t_agent_group* group;
	std::map<std::string, t_agent_group*>::iterator iter_group;
	std::map<HSOCKET, t_sheeps_agent*>::iterator iter_agent;
	for (size_t i = 0; i != ProjectConfig.size(); ++i) {
		projectcfg = ProjectConfig[i];
		for (iter_group = projectcfg->groups.begin(); iter_group != projectcfg->groups.end(); ++iter_group) {
			group = iter_group->second;
			for (iter_agent = group->agents->begin(); iter_agent != group->agents->end(); ++iter_agent){
				HsocketSend(iter_agent->first, buf, head.msgLen);
			}
		}
	}

	free(buf);
	return 0;
}

static int server_cmd_hertbaet(HSOCKET hsock, ServerProtocol* proto, int cmdNO, cJSON* root, cJSON* res)
{
	cJSON* cpu = cJSON_GetObjectItem(root, "cpu");
	cJSON* mem = cJSON_GetObjectItem(root, "memory");
	cJSON* adapter = cJSON_GetObjectItem(root, "bandwidth");
	proto->stressInfo->cpu_cast = cpu->valueint;
	proto->stressInfo->mem_cast = mem->valueint;
	proto->stressInfo->adapter_cast = adapter->valueint;
	cJSON_AddStringToObject(res, "ret", "OK");
	ResponseMsg(hsock, cmdNO, res);
	return 0;
}

static int server_cmd_report_agent_info(HSOCKET hsock, ServerProtocol* proto, int cmdNO, cJSON* root, cJSON* res)
{
	cJSON* cpu = cJSON_GetObjectItem(root, "CPU");
	cJSON* mem = cJSON_GetObjectItem(root, "Mem");
	cJSON* adapter = cJSON_GetObjectItem(root, "BandWidth");
	cJSON* projectid = cJSON_GetObjectItem(root, "ProjectID");
	cJSON* groupid = cJSON_GetObjectItem(root, "GroupID");
	cJSON* authtime = cJSON_GetObjectItem(root, "Time");
	if (!cpu || !mem || !adapter || !projectid || !groupid|| !authtime || 
		!cJSON_IsNumber(cpu) || !cJSON_IsNumber(mem) || !cJSON_IsNumber(adapter) ||
		!cJSON_IsNumber(projectid) || !cJSON_IsString(groupid) || !cJSON_IsNumber(authtime))
	{
		LOG(slogid, LOG_ERROR, "%s:%d error\r\n", __func__, __LINE__);
		return -1;
	}

	if (size_t(projectid->valueint) >= ProjectConfig.size()) {
		cJSON_AddNumberToObject(res, "ret", 1);
		cJSON_AddStringToObject(res, "msg", "项目不存在");
		ResponseMsg(hsock, cmdNO, res);
		HsocketClose(hsock);
		return -1;
	}

	t_sheeps_agent* agent = proto->stressInfo;
	HsocketPeerAddr(hsock, agent->ip, sizeof(agent->ip), &agent->port);
	agent->ready = AGENT_AUTH;
	agent->cpu = cpu->valueint;
	agent->mem_total = mem->valueint;
	agent->adapter = adapter->valueint;
	agent->projectid = projectid->valueint;
	snprintf(agent->groupid, sizeof(agent->groupid), "%s", groupid->valuestring);
	
	//PostEvent(server_hook, agent, [](BaseWorker* work, void* agent) {
	//	((ServerHookProtocol*)server_hook)->event_agent((t_sheeps_agent*)agent, "agent_connect");
	//	});
	if (server_hook) server_hook->event_agent(agent, "agent_connect");

	t_project_config* info = ProjectConfig[agent->projectid];
	t_agent_group* group;
	std::map<std::string, t_agent_group*>::iterator iter = info->groups.find(agent->groupid);
	if (iter != info->groups.end()) {
		group = iter->second;
		group->count++;
	}
	else {
		group = (t_agent_group*)malloc(sizeof(t_agent_group));
		memset(group, 0x0, sizeof(t_agent_group));
		group->agents = new std::map<HSOCKET, t_sheeps_agent*>;
		info->groups.insert(std::make_pair(agent->groupid, group));
	}
	group->count++;
	group->agents->insert(std::make_pair(hsock, agent));
	AgentTotalCount++;

	cJSON_AddNumberToObject(res, "ret", 0);
	ResponseMsg(hsock, cmdNO, res);
	sync_files(hsock, projectid->valueint);
	return 0;
}

static int server_cmd_download_file(HSOCKET hsock, ServerProtocol* proto, int cmdNO, cJSON* root, cJSON* res)
{
	LOG(slogid, LOG_DEBUG, "%s:%d\r\n", __func__, __LINE__);
	cJSON* file = cJSON_GetObjectItem(root, "File");
	cJSON* offset = cJSON_GetObjectItem(root, "Offset");
	cJSON* size = cJSON_GetObjectItem(root, "Size");
	if (file == NULL || offset == NULL || size == NULL){
		LOG(slogid, LOG_ERROR, "%s:%d parm error\r\n", __func__, __LINE__);
		return -1;
	}

	char fullpath[256] = { 0x0 };
	snprintf(fullpath, sizeof(fullpath), "%s/%s", EXE_Path, file->valuestring);
	FILE* hfile = NULL;
#ifdef __WINDOWS__
	int ret = fopen_s(&hfile, fullpath, "rb");
#else
	hfile = fopen(fullpath, "rb");
#endif // __WINDOWS__
	if (hfile == NULL){
		LOG(slogid, LOG_ERROR, "%s:%d open file error\r\n", __func__, __LINE__);
		return -1;
	}

#define FILEBUFLEN 10240
	int count = size->valueint / FILEBUFLEN;
	int last = size->valueint % FILEBUFLEN;

	char* buf = (char*)malloc(FILEBUFLEN);
	char* base64 = (char*)malloc(FILEBUFLEN);
	if (buf == NULL || base64 == NULL)
	{
		LOG(slogid, LOG_ERROR, "%s:%d memory error\r\n", __func__, __LINE__);
		goto end_free;
	}
	memset(buf, 0x0, FILEBUFLEN);
	memset(base64, 0x0, FILEBUFLEN);

	fseek(hfile, offset->valueint, SEEK_SET);

	for (int i = 0; i < count; i++)
	{
		fread(buf, sizeof(char), FILEBUFLEN, hfile);
		base64_encode(buf, FILEBUFLEN, base64);

		cJSON_AddStringToObject(res, "File", file->valuestring);
		cJSON_AddNumberToObject(res, "Offset", offset->valueint);
		cJSON_AddNumberToObject(res, "Order", i);
		cJSON_AddNumberToObject(res, "Size", FILEBUFLEN);
		cJSON_AddStringToObject(res, "Data", base64);
		cJSON_AddNumberToObject(res, "retCode", 0);
		cJSON_AddStringToObject(res, "retMsg", "OK");

		ResponseMsg(hsock, cmdNO, res);
		memset(buf, 0, FILEBUFLEN);
		memset(base64, 0, FILEBUFLEN);
	}
	if (size->valueint == 0 || last > 0)
	{
		fread(buf, sizeof(char), last, hfile);
		base64_encode(buf, last, base64);

		cJSON_AddStringToObject(res, "File", file->valuestring);
		cJSON_AddNumberToObject(res, "Offset", offset->valueint);
		cJSON_AddNumberToObject(res, "Order", count);
		cJSON_AddNumberToObject(res, "Size", last);
		cJSON_AddStringToObject(res, "Data", base64);
		cJSON_AddNumberToObject(res, "retCode", 0);
		cJSON_AddStringToObject(res, "retMsg", "OK");

		ResponseMsg(hsock, cmdNO, res);
		memset(buf, 0, FILEBUFLEN);
		memset(base64, 0, FILEBUFLEN);
	}

end_free:
	fclose(hfile);
	free(buf);
	free(base64);
	return 0;
}

static int server_cmd_sync_files_over(HSOCKET hsock, ServerProtocol* proto, int cmdNO, cJSON* root, cJSON* res)
{
	cJSON* ret = cJSON_GetObjectItem(root, "retCode");
	t_sheeps_agent* agent = proto->stressInfo;
	if (ret && cJSON_IsNumber(ret))
	{
		if (ret->valueint == 0)
			agent->ready = AGENT_READY;
		else
			agent->ready = AGENT_FAIL;
	}
	return 0;
}

static void server_cmd_agent_report_data_task_stop(hServerTaskConfig taskcfg, cJSON* error) {
	int ctime = (int)NOWTIME;
	int size = cJSON_GetArraySize(error);
	for (int i = 0; i < size; i++) {
		char* value = cJSON_GetArrayItem(error, i)->valuestring;
		int machine_id = atoi(value);
		char* p = strchr(value, '|');
		int user_number = atoi(p+1);
		p = strchr(p + 1, '|');
		int run_time = atoi(p + 1);
		p = strchr(p + 1, '|');
		char* msg = p + 1;
		task_user_dead(ctime, taskcfg, machine_id, user_number, run_time, msg);
	}
}

static inline void server_cmd_agent_report_data_task_online(hServerTaskConfig taskcfg, cJSON* online){
	task_user_online_count(taskcfg, online->valueint);
}

static void server_cmd_agent_report_data_task_connect(hServerTaskConfig taskcfg, cJSON* connect) {
	int size = cJSON_GetArraySize(connect);
	for (int i = 0; i < size; i++) {
		cJSON* item = cJSON_GetArrayItem(connect, i);
		cJSON* addr = cJSON_GetObjectItem(item, "addr");
		cJSON* success = cJSON_GetObjectItem(item, "success");
		cJSON* faile = cJSON_GetObjectItem(item, "faile");
		cJSON* flow_up = cJSON_GetObjectItem(item, "flow_up");
		cJSON* flow_down = cJSON_GetObjectItem(item, "flow_down");
		cJSON* net_flow_up = cJSON_GetObjectItem(item, "net_flow_up");
		cJSON* net_flow_down = cJSON_GetObjectItem(item, "net_flow_down");
		int connect_success = success ? success->valueint : 0;
		int connect_faile = faile ? faile->valueint : 0;
		int connect_flow_up = flow_up ? flow_up->valueint : 0;
		int connect_flow_down = flow_down ? flow_down->valueint : 0;
		int connect_net_flow_up = net_flow_up ? net_flow_up->valueint : 0;
		int connect_net_flow_down = net_flow_down ? net_flow_down->valueint : 0;
		task_user_connect_result(taskcfg, addr->valuestring, connect_success, connect_faile);
		task_user_netflow(taskcfg, addr->valuestring, connect_flow_up, connect_flow_down, connect_net_flow_up, connect_net_flow_down);
	}
}

static void server_cmd_agent_report_data_task_counter(hServerTaskConfig taskcfg, cJSON* counter) {
	int size = cJSON_GetArraySize(counter);
	for (int i = 0; i < size; i++) {
		cJSON* item = cJSON_GetArrayItem(counter, i);
		cJSON* name = cJSON_GetObjectItem(item, "name");
		cJSON* value = cJSON_GetObjectItem(item, "value");
		cJSON* stype = cJSON_GetObjectItem(item, "stype");
		cJSON* space_time = cJSON_GetObjectItem(item, "space_time");
		task_user_counter(taskcfg, name->valuestring, value->valueint, stype->valueint, space_time->valueint);
	}
}

static void server_cmd_agent_report_data_task_api(hServerTaskConfig taskcfg, cJSON* api) {
	int size = cJSON_GetArraySize(api);
	for (int i = 0; i < size; i++) {
		cJSON* item = cJSON_GetArrayItem(api, i);
		cJSON* name = cJSON_GetObjectItem(item, "name");
		cJSON* send_flow = cJSON_GetObjectItem(item, "send_flow");
		cJSON* send_count = cJSON_GetObjectItem(item, "send_count");
		cJSON* recv_flow = cJSON_GetObjectItem(item, "recv_flow");
		cJSON* recv_count = cJSON_GetObjectItem(item, "recv_count");
		cJSON* error = cJSON_GetObjectItem(item, "error");
		cJSON* response_time = cJSON_GetObjectItem(item, "response_time");
		task_user_api(taskcfg, name->valuestring, 
			send_flow ? send_flow->valueint : 0, send_count ? send_count->valueint : 0,
			recv_flow ? recv_flow->valueint : 0, recv_count ? recv_count->valueint : 0,
			error ? error->valueint : 0, response_time ? response_time : NULL);
	}
}

static void server_cmd_agent_report_data_task(cJSON* task) {
	cJSON* task_id = cJSON_GetObjectItem(task, "task_id");
	cJSON* run_number = cJSON_GetObjectItem(task, "run_number");
	hServerTaskConfig taskcfg = task_report_timeout(task_id->valueint, run_number->valueint);
	if (!taskcfg) return;
	cJSON* error = cJSON_GetObjectItem(task, "error");
	if (error) server_cmd_agent_report_data_task_stop(taskcfg, error);
	cJSON* online = cJSON_GetObjectItem(task, "online");
	if (online) server_cmd_agent_report_data_task_online(taskcfg, online);
	cJSON* connect = cJSON_GetObjectItem(task, "connect");
	if (connect) server_cmd_agent_report_data_task_connect(taskcfg, connect);
	cJSON* counter = cJSON_GetObjectItem(task, "counter");
	if (counter) server_cmd_agent_report_data_task_counter(taskcfg, counter);
	cJSON* api = cJSON_GetObjectItem(task, "api");
	if (api) server_cmd_agent_report_data_task_api(taskcfg, api);
}

static int server_cmd_agent_report_data(HSOCKET hsock, ServerProtocol* proto, int cmdNO, cJSON* root, cJSON* res){
	cJSON* array_task = cJSON_GetObjectItem(root, "data");
	int task_size = cJSON_GetArraySize(array_task);
	for (int i = 0; i < task_size; i++) {
		cJSON* task = cJSON_GetArrayItem(array_task, i);
		server_cmd_agent_report_data_task(task);
	}
	return 0;
}

static int server_cmd_user_report(HSOCKET hsock, ServerProtocol* proto, int cmdNO, cJSON* root, cJSON* res)
{
	cJSON* events = cJSON_GetObjectItem(root, "events");
	if (!events || !cJSON_IsArray(events)) return -1;
	int eventsz = cJSON_GetArraySize(events);
	cJSON* item = NULL;
	char *data, *msg = NULL;
	size_t  size = 0;
	for (int i = 0; i < eventsz; i++)
	{
		item = cJSON_GetArrayItem(events, i);
		data = item->valuestring;
		size = strlen(data);
		msg = base64decode(data, size, &size);
		free(msg);
	}
	return 0;
}

static int server_cmd_user_report_log(HSOCKET hsock, ServerProtocol* proto, int cmdNO, cJSON* root, cJSON* res) {
	cJSON* task_id = cJSON_GetObjectItem(root, "task_id");
	cJSON* file = cJSON_GetObjectItem(root, "file");
	cJSON* data = cJSON_GetObjectItem(root, "data");

	char fullpath[256] = { 0x0 };
	snprintf(fullpath, sizeof(fullpath), "%stasklog%c%d%c%s", EXE_Path, DIRChar, task_id->valueint, DIRChar, file->valuestring);

	CreateFileDirectory(fullpath);

	FILE* hfile = NULL;
#ifdef __WINDOWS__
	fopen_s(&hfile, fullpath, "ab+");
#else
	hfile = fopen(fullpath, "ab+");
#endif
	fwrite(data->valuestring, sizeof(char), data->valueint, hfile);
	fclose(hfile);

	cJSON_AddNumberToObject(res, "task_id", task_id->valueint);
	ResponseMsg(hsock, C2S_Task_Report_Log, res);
	return 0;
}

static int server_cmd_user_report_log_done(HSOCKET hsock, ServerProtocol* proto, int cmdNO, cJSON* root, cJSON* res) {
	cJSON* task_id = cJSON_GetObjectItem(root, "task_id");
	if (!task_id || !cJSON_IsNumber(task_id)) return -1;

	hServerTaskConfig taskcfg = get_server_taskcfg_by_id(task_id->valueint);
	if (!taskcfg) return -1;
	hServerTaskRun taskrun = taskcfg->taskrun;
	if (!taskrun) return -1;
	taskrun->report_log--;
	return 0;
}

std::map<int, serverStress_cmd_cb> ServerFunc{
	{C2S_Agent_Hertbaet,		server_cmd_hertbaet},
	{C2S_Agent_Report_Info,		server_cmd_report_agent_info},
	{C2S_Agent_Download_File,	server_cmd_download_file},
	{C2S_Agent_File_Sync_Done,	server_cmd_sync_files_over},
	{C2S_Agent_Report_Date,		server_cmd_agent_report_data},
	{C2S_Task_Report_Events,	server_cmd_user_report},
	{C2S_Task_Report_Log,		server_cmd_user_report_log},
	{C2S_Task_Report_Log_Done,	server_cmd_user_report_log_done}
};

static void do_server_func_by_cmd(HSOCKET hsock, ServerProtocol* proto, int cmdNO, cJSON* root, cJSON* res)
{
	std::map<int, serverStress_cmd_cb>::iterator iter = ServerFunc.find(cmdNO);
	if (iter != ServerFunc.end())
		iter->second(hsock, proto, cmdNO, root, res);
}

int CheckStressRequest(HSOCKET hsock,ServerProtocol* proto , const char* data, int len){
	if (len < (int)SHEEPS_HEAD_SIZE)
		return 0;
	t_stress_protocol_head head;
	memcpy(&head, data, SHEEPS_HEAD_SIZE);
	if (len < head.msgLen)
		return 0;
	int clen = head.msgLen - SHEEPS_HEAD_SIZE;
	LOG(slogid, LOG_DEBUG, "%s:%d [%d %d][%.*s]\r\n", __func__, __LINE__, head.msgLen, head.cmdNo, clen, data + SHEEPS_HEAD_SIZE);

	cJSON* root = head.binary ? cJSON_ParseBinary(data + SHEEPS_HEAD_SIZE, clen) : cJSON_ParseByte(data + SHEEPS_HEAD_SIZE, clen);
	if (root == NULL){
		LOG(slogid, LOG_ERROR, "%s:%d cjson decode error\r\n", __func__, __LINE__);
		return -1;
	}
	cJSON* res = cJSON_CreateObject();
	if (!res){
		cJSON_Delete(root);
		return -1;
	}
	do_server_func_by_cmd(hsock, proto, head.cmdNo, root, res);
	cJSON_Delete(root);
	cJSON_Delete(res);
	return head.msgLen;
}

void StressConnectionClosed(HSOCKET hsock, ServerProtocol* proto)
{
	LOG(slogid, LOG_DEBUG, "%s:%d %p\r\n", __func__, __LINE__, hsock);
	t_sheeps_agent* agent = proto->stressInfo;

	//PostEvent(server_hook, agent, [](BaseWorker* work, void* agent) {
	//	((ServerHookProtocol*)server_hook)->event_agent((t_sheeps_agent*)agent, "agent_disconnect");
	//	});
	if (server_hook) server_hook->event_agent(agent, "agent_disconnect");

	if (agent->ready >= AGENT_AUTH && agent->projectid < ProjectConfig.size()) {
		t_project_config* info = ProjectConfig[agent->projectid];
		t_agent_group* group;
		std::map<std::string, t_agent_group*>::iterator iter = info->groups.find(agent->groupid);
		if (iter != info->groups.end()) {
			group = iter->second;
			group->count--;
			group->agents->erase(hsock);
			if (group->count == 0 && strcmp(agent->groupid, DEFAUT_GROUP) != 0 ) {
				delete group->agents;
				free(group);
				info->groups.erase(iter);
			}
		}
		AgentTotalCount--;
	}
	proto->initSock = NULL;
}